package tr3dtris.game;

import java.util.Vector;
import tr3dtris.game.display.AbstractDisplay;
import tr3dtris.game.models.CellArray;
import tr3dtris.game.models.pieces.AbstractPiece;

/**
 * Principal Game class. Collects and coordinates all the objects needed for
 * playing a single match of the game.
 * @author Luciano Mammino <loige@hotmail.com>
 * @author Andrea Mangano <kapitan0@hotmail.it>
 * @version 0.1
 * @since 0.1
 */
public class Game
{

    /**
     * Vector used to list all the <AbstractDisplay>s
     * connected to the game
     */
    private Vector<AbstractDisplay> displayList;

    /**
     * <CellArray> used to rapresents the game grid (or game board)
     */
    private CellArray grid;

    /**
     * <AbstractPiece> used for the current falling piece
     */
    private AbstractPiece currentPiece;

    /**
     * <AbstractPiece> used to display the next falling piece.
     * When the currentPiece falls down the nextPiece became the new
     * currentPiece and a new nextPiece is randomly created
     */
    private AbstractPiece nextPiece;

    /**
     * Connected class used to manage all the game actions like starting the
     * game, moving pieces, etc.
     */
    private GameActions gameActions;

    /**
     * Connected class used to manage the whole game logic
     */
    private GameLogic gameLogic;

    /**
     * Connected class used to fire game events
     */
    private GameEvents gameEvents;

    /**
     * Counts the points obtained while playing
     */
    private int points;

    /**
     * Counts the number of block lines removed while playing
     */
    private int linesErased;

    /**
     * Flag used to pause the game
     */
    private boolean paused;

    /**
     * flag used to restart game from pause
     */
    private boolean playing;

    /**
     * flag used when the game is over
     */
    private boolean gameOver;

    /**
     * Constructor. Creates a new <Game> without a display;
     */
    public Game()
    {
        this(null);
    }

    /**
     * Constructor. Creates a new <Game> with a default <AbstractDisplay>
     * @param display the default <AbstractDisplay>
     */
    public Game(AbstractDisplay display)
    {
        this.displayList = new Vector<AbstractDisplay>();
        this.grid = new CellArray();
        this.gameActions = new GameActions(this);
        this.gameLogic = new GameLogic(this);
        this.gameEvents = new GameEvents();
        if(display != null)
            this.addDisplay(display);
    }


    /**
     * Adds a new <AbstractDislay> in the display vector
     * @param display
     */
    public void addDisplay(AbstractDisplay display)
    {
        this.displayList.add(display);
        display.setGame(this);
        display.configure();
    }

    /**
     * Iterate and refresh all the <AbstractDisplay>s connected
     */
    public void refreshAllDisplay()
    {
        for(int i=0; i < this.displayList.size(); i++)
        {
            this.displayList.get(i).refresh();
        }
    }
    

    /**
     * @return the first display in the #displayList
     */
    public AbstractDisplay getFirstDisplay()
    {
        return this.displayList.firstElement();
    }

    /**
     * @return the grid
     */
    public CellArray getGrid()
    {
        return grid;
    }

    /**
     * @return the currentPiece
     */
    public AbstractPiece getCurrentPiece()
    {
        return currentPiece;
    }

    /**
     * @return the nextPiece
     */
    public AbstractPiece getNextPiece()
    {
        return nextPiece;
    }

    /**
     * @return the points
     */
    public int getPoints()
    {
        return points;
    }

    /**
     * @return the blocksRemoved
     */
    public int getLinesErased()
    {
        return linesErased;
    }

    /**
     * @return the paused
     */
    public boolean isPaused()
    {
        return paused;
    }

    /**
     * @return the playing
     */
    public boolean isPlaying()
    {
        return playing;
    }

    /**
     * @return the gameOver
     */
    public boolean isGameOver()
    {
        return gameOver;
    }

    /**
     * @return the displayList
     */
    public Vector<AbstractDisplay> getDisplayList() {
        return displayList;
    }

    /**
     * @param displayList the displayList to set
     */
    public void setDisplayList(Vector<AbstractDisplay> displayList) {
        this.displayList = displayList;
    }

    /**
     * @return the gameActions
     */
    public GameActions getGameActions()
    {
        return gameActions;
    }

    /**
     * @param currentPiece the currentPiece to set
     */
    public void setCurrentPiece(AbstractPiece currentPiece) {
        this.currentPiece = currentPiece;
    }

    /**
     * @param nextPiece the nextPiece to set
     */
    public void setNextPiece(AbstractPiece nextPiece) {
        this.nextPiece = nextPiece;
    }

    /**
     * @param paused the paused to set
     */
    public void setPaused(boolean paused) {
        this.paused = paused;
    }

    /**
     * @param playing the playing to set
     */
    public void setPlaying(boolean playing) {
        this.playing = playing;
    }

    /**
     * @param gameOver the gameOver to set
     */
    public void setGameOver(boolean gameOver) {
        this.gameOver = gameOver;
    }

    /**
     * @return the gameLogic
     */
    public GameLogic getGameLogic() {
        return gameLogic;
    }

    /**
     * @param points the points to set
     */
    public void setPoints(int points) {
        this.points = points;
    }

    /**
     * @param linesErased the linesErased to set
     */
    public void setLinesErased(int linesErased) {
        this.linesErased = linesErased;
    }

    /**
     * Adds a given amount of points
     * @param points
     */
    public void addPoints(int points)
    {
        this.points += points;
    }

    /**
     * Add a given amount of erased lines
     * @param lines
     */
    public void addLinesErased(int lines)
    {
        this.linesErased += lines;
    }

    /**
     * @return the gameEvents
     */
    public GameEvents getGameEvents() {
        return gameEvents;
    }

    /**
     * @param gameEvents the gameEvents to set
     */
    public void setGameEvents(GameEvents gameEvents) {
        this.gameEvents = gameEvents;
    }

}